﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace calculator
{
    public class BooleanCalculator
    {
        public TruthTable calculate(string expression)
        {
            //klasinn gerir instance af eftirfarandi hlutum sem þarf fyrir útreikningana
            ExpressionString expressionString = new ExpressionString(expression);
            TruthTable table = new TruthTable(expression);

            table = fillInitialVariables(table, expressionString.getVarList());

            List<string> exString = new List<string>();
            exString = expressionString.getExpressionList();
         
          
            //While loopa sem fer í gegnum strengin á meðan það er svigi í expressioninu
            while (exString.IndexOf("(") != -1)
            {
                List<string> tempList = new List<string>();
                int x = exString.LastIndexOf("(") + 1;
                int y = exString.IndexOf(")",x) - x;
                tempList = exString.GetRange(x, y);
                table = calculateExpression(table, tempList, expressionString.getVarList().Length);
                exString.RemoveRange(x - 1, y + 2);
                exString.Insert(x-1,table.getRow(table.getLength()-1).getName());
            }
            table = calculateExpression(table, exString, expressionString.getVarList().Length);
   
            return table;
        }

        private TruthTable calculateExpression(TruthTable table, List<string> expressionList,int varCount)
        {
            PerformOperation p = new PerformOperation();
            string[] operators = {"AND","NAND","XNOR","OR","NOR","XOR","IFN","IFF"};
            List<string> list = expressionList;

            while(list.IndexOf("NOT") != -1)
            {
                int loc = list.IndexOf("NOT");
                string rowName = list[loc] + " " + list[loc+1];
                TruthTableRow row = new TruthTableRow((int)Math.Pow(2,varCount),rowName,table.getLength());
                row.setRow(p.resultOfOperation(table.findRow(list[loc + 1]).getRow(), "NOT"));
                list.RemoveRange(loc,2);
                list.Insert(loc,rowName);
                table.addRow(row);
            }
            //Fer í gegnum alla operatora sem eru til í réttri priority röð og athugar hvort að þeir eru til
            for (int i = 0; i < operators.Length; i++)
            {
                if (list.IndexOf(operators[i]) != -1)
                {
                    int loc = list.IndexOf(operators[i]);
                    string rowName =  list[loc - 1] + " " + list[loc] + " " +list[loc + 1];
                    //Stærð raðarinnar ákvarðast útfrá 2 í veldi fjölda breyta, í þessu tilviki 2 í öðru
                    TruthTableRow row = new TruthTableRow((int)Math.Pow(2, varCount), rowName, table.getLength());
                    row.setRow(p.resultOfOperation(table.findRow(list[loc - 1]).getRow(), table.findRow(list[loc +1]).getRow(), operators[i]));

                    list.RemoveRange(loc-1,3 );
                    list.Insert(loc-1, rowName);
                    table.addRow(row);
                    i--;
                }
            }
            return table;
        }
        //Fall sem setur inn byrjunar breytunar og frumstillir þær
        private TruthTable fillInitialVariables(TruthTable table, char[] varList)
        {
            for (int i = 0; i < varList.Length; i++)
            {
                //stærð raðarinnar fæst með því að vita hversu margar breytur eru í expressioninu
                //stærðin er svo 2 í því veldi
                TruthTableRow row = new TruthTableRow((int)Math.Pow(2, varList.Length), varList[i].ToString(), i);
                table.addRow(row);
            }

            BinaryString binaryGenerator = new BinaryString();
            for (int i = 0; i < (int)Math.Pow(2,varList.Length); i++)
            {
                string binaryString = binaryGenerator.addTrailingZeros(varList.Length, i);
                for (int j = 0; j < varList.Length; j++)
                {
                    table.getRow(j).setValue(i, getBoolValue(binaryString[j]));
                }
            }
            return table;
        }
        private bool getBoolValue(char binary)
        {
            if (binary == '0')
                return true;
            return false;
        }
        
    }
}